/*
 *
 */
package sentinel;

import com.alibaba.csp.sentinel.Entry;
import com.alibaba.csp.sentinel.SphU;
import com.alibaba.csp.sentinel.Tracer;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.alibaba.csp.sentinel.slots.block.RuleConstant;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor;
import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

public class SentinelInterceptor implements InstanceMethodsAroundInterceptor {
    static final ThreadLocal<Entry> ENTRY_THREAD_LOCAL = new ThreadLocal<Entry>();

    @Override
    public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes, MethodInterceptResult result) throws Throwable {
        System.out.println("beforeMethod sentinel....");

        Entry entry = null;
        try {
            //流控规则初始化
            //initFlowRules();
            //流控代码
            String resourceName=getResourceName(objInst,method,argumentsTypes);
            System.out.println("resourceName="+resourceName);
            entry= SphU.entry(resourceName);
            ENTRY_THREAD_LOCAL.set(entry);
            //业务代码
        } catch (BlockException ex) {
            System.out.println("[queryUser] has been projected! Time="+System.currentTimeMillis() );
            result.defineReturnValue("blocking");
        } catch (Throwable ex) {
            Tracer.trace(ex);
            throw ex;
        }
    }

    @Override
    public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes, Object ret) throws Throwable {
        System.out.println("afterMethod sentinel....");
        Entry entry = ENTRY_THREAD_LOCAL.get();
        if (entry != null) {

            entry.exit();
        }
        return ret;
    }

    @Override
    public void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes, Throwable t) {
        Entry entry = ENTRY_THREAD_LOCAL.get();
        if (entry != null) {
            if (t != null) {
                Tracer.traceEntry(t, entry);
            }
            entry.exit();
        }
        //Tracer.traceEntry(t, entry);
        System.out.println("exception");
    }

    private String getResourceName(EnhancedInstance objInst, Method method, Class<?>[] argumentsTypes){
        StringBuilder buf = new StringBuilder(64);
        buf.append(objInst.getClass().getName())
                .append(":")
                .append(method.getName())
                .append("(");
        boolean isFirst = true;
        for (Class<?> clazz : argumentsTypes) {
            if (!isFirst) {
                buf.append(",");
            }
            buf.append(clazz.getSimpleName());
            isFirst = false;
        }
        buf.append(")");

        return buf.toString();
    }

    /*private static void initFlowRules() {
        List<FlowRule> rules = new ArrayList<>();
        FlowRule rule = new FlowRule();
        rule.setResource("aaaaass");
        rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
        rule.setCount(1);
        rules.add(rule);
        FlowRuleManager.loadRules(rules);
    }*/
}
